using System;
using System.Collections.Generic;
using System.Text;
namespace JobShopModel.Model.FactoryLvl
{
    /// <summary>
    /// Class time 
    /// TODO: Finish documentation
    /// Time can represent the duration of an element but also the time it should start
    /// </summary>
    public class Time:IComparable<Time>
    {
        private int days;
        private Decimal hours;

        #region Constructors

        /// <summary>
        /// Default COnstructor
        /// </summary>
        /// <param name="day">day to be set</param>
        /// <param name="hour">hour to be set</param>
        public Time(int day, Decimal hour)
        {
            Days = day;
            Hours = hour;
        }

        /// <summary>
        /// Another COnstructor
        /// </summary>
        /// <param name="hours">Hour to be set</param>
        public Time(Decimal hours)
            :this(0,hours)
        {}

        /// <summary>
        /// Another Constructor
        /// </summary>
        /// <param name="days">Day to be set</param>
        public Time(int days)
            :this(days,(Decimal)0.0)
        { }

        /// <summary>
        /// Empty Constructor
        /// Init the time at 0 days,0.0 hours
        /// </summary>
        public Time()
            :this(0,(Decimal)0.0)
        { }

        #endregion Constructors

        /// <summary>
        /// Public Hours Properties.
        /// Automaticaly increments de days when added hours.
        /// </summary>
        public Decimal Hours
        {
            set
            {
                //hours can't be negative
                if (value >= new Decimal(0.0))
                {
                    Decimal tmp =  value;

                    //if hours inserted > 1 day
                    if (tmp > 24)
                    {
                        do
                        {
                            //increment days
                            this.days++;
                            //if hours still > 24
                            if(tmp >= 24)
                                //subtract the day from the hours
                                tmp -= 24;
                        } while (tmp >= 24);
                        //end after the hours are reduced to fewer than 24
                        this.Hours = tmp;
                    }
                    else
                    {
                        this.hours = value;
                    }
                }
            }
            get { return this.hours; }
        }

        /// <summary>
        /// Public days property
        /// </summary>
        public int Days
        {
            set
            {
                if (value >= 0)
                {
                    this.days = value;
                }
            }

            get { return this.days; }
        }

        /// <summary>
        /// Equals Method overriden
        /// </summary>
        /// <param name="obj">Object ot be compared</param>
        /// <returns>true if equals, false otherwise</returns>
        public override bool Equals(object obj)
        {
            if ( !(obj is Time))
            {
                return false;
            }
            else
            {
                Time tmp = (Time)obj;
                if (tmp.Days == this.Days && tmp.Hours == this.Hours)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Needed to overide Equals
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Overloaded comparison
        /// </summary>
        /// <param name="t1">first element</param>
        /// <param name="t2">seconde element</param>
        /// <returns> true if t1 less that t2</returns>
        public static bool operator < (Time t1,Time t2){
            if (t1.days < t2.days)
                return true;
            else if (t1.days > t2.days)
                return false;
            else
            //t1.days == t2.days
            {
                if (t1.hours < t2.hours)
                    return true;
                else
                    return false;
            }
        }

        /// <summary>
        /// Overloaded operator sup
        /// </summary>
        /// <param name="t1">first element</param>
        /// <param name="t2">seconde element</param>
        /// <returns> true if t1 more that t2</returns>
        public static bool operator >(Time t1, Time t2)
        {
            if (t1.days > t2.days)
                return true;
            else if (t1.days < t2.days)
                return false;
            else
            //t1.days == t2.days
            {
                if (t1.hours > t2.hours)
                    return true;
                else
                    return false;
            }
        }

        /// <summary>
        /// Method for multiplying a time by an integer
        /// </summary>
        /// <param name="t1">Time value</param>
        /// <param name="t2">Integer value</param>
        /// <returns>Number of hours in t1 * value of t2</returns>
        public static Time operator * (Time t1,int t2)
        {
            Decimal hourstotal = (t1.Days * 24) + t1.Hours;
            hourstotal = hourstotal * t2;

            return new Time(hourstotal);
        }

        /// <summary>
        /// Overloaded operator +
        /// </summary>
        /// <param name="t1">first element</param>
        /// <param name="t2">seconde element</param>
        /// <returns> sum of t1 + t2</returns>
        public static Time operator + (Time t1,Time t2)
        {
            Time tmptime = new Time();
            int tmpdays = t1.Days + t2.Days;
            Decimal tmphours = new Decimal();
            tmphours = t1.Hours + t2.Hours;

            tmptime.Days = tmpdays;
            tmptime.Hours = tmphours;
            //so that it will roll over days if hours exceed 24
            return tmptime;
        }

        /// <summary>
        /// Overloaded operator -
        /// </summary>
        /// <param name="t1">first element</param>
        /// <param name="t2">seconde element</param>
        /// <returns> sub of T1 and t2</returns>
        public static Time operator -(Time t1, Time t2)
        {
            Time tmptime = new Time();
            int subDays = t1.Days - t2.Days;
            Decimal subHours = t1.Hours - t2.Hours;

            tmptime.Hours = subHours;
            tmptime.Days = subDays;

            return tmptime;
        }

        /// <summary>
        /// Operator allowing two times to be divided
        /// </summary>
        /// <param name="t1">Time 1</param>
        /// <param name="t2">Time 2</param>
        /// <returns>(Time 1 in hours)/(Time 2 in hours)</returns>
        public static Decimal operator /(Time t1, Time t2)
        {
            Decimal hours1 = (Decimal)t1.Days * 24 + t1.Hours;
            Decimal hours2 = (Decimal)t2.Days * 24 + t1.Hours;

            return hours1 / hours2;
        }

        /// <summary>
        /// Operator to divide a time by a decimal
        /// </summary>
        /// <param name="t1">Time</param>
        /// <param name="t2">Decimal</param>
        /// <returns>(Time in hours)/Decimal</returns>
        public static Time operator /(Time t1, Decimal t2)
        {
            Decimal hours1 = (Decimal)t1.Days * 24 + t1.Hours;

            return new Time(hours1 / t2);
        }

        /// <summary>
        /// ToString overload
        /// </summary>
        /// <returns> Formated time</returns>
        public override string ToString()
        {
            return String.Format("{0}days, {1:0.##}hours",Days,Hours);
        }

        #region IComparable<Time> Membres

        public int CompareTo(Time other)
        {
            Decimal hours1 = (Decimal)this.Days * 24 + this.Hours;
            Decimal hours2 = (Decimal)other.Days * 24 + other.Hours;

            return hours1.CompareTo(hours2);
        }

        #endregion
    }
}
